/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                        Intel License Agreement
//
// Copyright (C) 2000, Intel Corporation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of Intel Corporation may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/

#include "precomp.hpp"

typedef struct DefBlobTrack {
	CvBlob      blob;
	CvBlobSeq*  pSeq;
	int         FrameBegin;
	int         FrameLast;
	int         Saved; /* flag */
} DefBlobTrack;

class CvBlobTrackGenYML: public CvBlobTrackGen {
protected:
	int         m_Frame;
	char*       m_pFileName;
	CvBlobSeq   m_TrackList;
	CvSize      m_Size;

	void SaveAll() {
		int     ObjNum = m_TrackList.GetBlobNum();
		int     i;
		char    video_name[1024];
		char*   struct_name = NULL;
		CvFileStorage* storage = cvOpenFileStorage(m_pFileName, NULL, CV_STORAGE_WRITE_TEXT);

		if (storage == NULL) {
			printf("WARNING!!! Cannot open %s file for trajectory output.", m_pFileName);
		}

		for (i = 0; i < 1024 && m_pFileName[i] != '.' && m_pFileName[i] != 0; ++i) { video_name[i] = m_pFileName[i]; }
		video_name[i] = 0;

		for (; i > 0; i--) {
			if (video_name[i-1] == '\\') { break; }
			if (video_name[i-1] == '/') { break; }
			if (video_name[i-1] == ':') { break; }
		}
		struct_name = video_name + i;

		cvStartWriteStruct(storage, struct_name, CV_NODE_SEQ);

		for (i = 0; i < ObjNum; ++i) {
			char            obj_name[1024];
			DefBlobTrack*   pTrack = (DefBlobTrack*)m_TrackList.GetBlob(i);
			if (pTrack == NULL) { continue; }
			sprintf(obj_name, "%s_obj%d", struct_name, i);
			cvStartWriteStruct(storage, NULL, CV_NODE_MAP);
			cvWriteInt(storage, "FrameBegin", pTrack->FrameBegin);
			cvWriteString(storage, "VideoObj", obj_name);
			cvEndWriteStruct( storage );
			pTrack->Saved = 1;
		}
		cvEndWriteStruct( storage );

		for (i = 0; i < ObjNum; ++i) {
			char            obj_name[1024];
			DefBlobTrack*   pTrack = (DefBlobTrack*)m_TrackList.GetBlob(i);
			CvBlobSeq*      pSeq = pTrack->pSeq;
			sprintf(obj_name, "%s_obj%d", struct_name, i);
			cvStartWriteStruct(storage, obj_name, CV_NODE_MAP);

			{
				/* Write position: */
				int             j;
				CvPoint2D32f    p;
				cvStartWriteStruct(storage, "Pos", CV_NODE_SEQ | CV_NODE_FLOW);
				for (j = 0; j < pSeq->GetBlobNum(); ++j) {
					CvBlob* pB = pSeq->GetBlob(j);
					p.x = pB->x / (m_Size.width - 1);
					p.y = pB->y / (m_Size.height - 1);
					cvWriteRawData(storage, &p, 1 , "ff");
				}
				cvEndWriteStruct( storage );
			}

			{
				/* Write size: */
				int             j;
				CvPoint2D32f    p;
				cvStartWriteStruct(storage, "Size", CV_NODE_SEQ | CV_NODE_FLOW);

				for (j = 0; j < pSeq->GetBlobNum(); ++j) {
					CvBlob* pB = pSeq->GetBlob(j);
					p.x = pB->w / (m_Size.width - 1);
					p.y = pB->h / (m_Size.height - 1);
					cvWriteRawData(storage, &p, 1 , "ff");
				}
				cvEndWriteStruct( storage );
			}
			cvEndWriteStruct( storage );
		}
		cvReleaseFileStorage(&storage);

	}   /* Save All */

public:
	CvBlobTrackGenYML(): m_TrackList(sizeof(DefBlobTrack)) {
		m_Frame = 0;
		m_pFileName = NULL;
		m_Size = cvSize(2, 2);

		SetModuleName("YML");
	};

	~CvBlobTrackGenYML() {
		int i;
		SaveAll();

		for (i = m_TrackList.GetBlobNum(); i > 0; --i) {
			DefBlobTrack* pTrack = (DefBlobTrack*)m_TrackList.GetBlob(i - 1);
			/* Delete sequence: */
			delete pTrack->pSeq;
			pTrack->pSeq = NULL;
		}   /* Check next track. */

	}   /* Destructor. */

	void    SetFileName(char* pFileName) {m_pFileName = pFileName;};
	void    AddBlob(CvBlob* pBlob) {
		DefBlobTrack* pTrack = (DefBlobTrack*)m_TrackList.GetBlobByID(CV_BLOB_ID(pBlob));

		if (pTrack == NULL) {
			/* Add new track: */
			DefBlobTrack    Track;
			Track.blob = pBlob[0];
			Track.FrameBegin = m_Frame;
			Track.pSeq = new CvBlobSeq;
			Track.Saved = 0;
			m_TrackList.AddBlob((CvBlob*)&Track);
			pTrack = (DefBlobTrack*)m_TrackList.GetBlobByID(CV_BLOB_ID(pBlob));
		}   /* Add new track. */

		assert(pTrack);
		pTrack->FrameLast = m_Frame;
		assert(pTrack->pSeq);
		pTrack->pSeq->AddBlob(pBlob);
	};
	void    Process(IplImage* pImg = NULL, IplImage* /*pFG*/ = NULL) {
		int i;
		m_Size = cvSize(pImg->width, pImg->height);

		for (i = m_TrackList.GetBlobNum(); i > 0; --i) {
			DefBlobTrack* pTrack = (DefBlobTrack*)m_TrackList.GetBlob(i - 1);

			if (pTrack->FrameLast < m_Frame && !pTrack->Saved) {
				/* Save track: */
				SaveAll();
			}   /* Save track. */

		}   /* Check next track. */

		m_Frame++;
	}

	void Release() {
		delete this;
	}
};  /* class CvBlobTrackGenYML */


CvBlobTrackGen* cvCreateModuleBlobTrackGenYML() {
	return (CvBlobTrackGen*) new CvBlobTrackGenYML;
}


